package reflect

import (
	"com/study/types"
	"com/study/util"
	"reflect"
)

// 反射
// 1.反射可以在运行的时候动态获取变量的各种信息，比如变量类型，变量类别
// 2.同样可以获取结构图的信息，包括字段、方法
// 3.通过反射，还可以修改变量的值，可以调用关联的方法
// 重要概念：interface{}、 reflect.Value、 变量是可以相互转换的
func Reflect(interfaceA interface{}) {
	// 1.interface{} 转为 reflect.Value
	reflectValue := reflect.ValueOf(interfaceA)
	util.PrnType(reflectValue)
	// 2.reflect.Value 转为 interface{}
	interfaceA = reflectValue.Interface()
	// 3.将interface{} 转为 原类型 - 断言转换
	i, ok := interfaceA.(int)
	if ok {
		util.PrnType(i)
	}
	stu2, ok := interfaceA.(types.Stu2)
	if ok {
		util.PrnType(stu2)
	}

	if IsStruct(interfaceA) {
		util.PrnLine()
		// 获取结构体的字段数量 NumField
		// 遍历结构体字段
		for i := 0; i < reflectValue.NumField(); i++ {
			// 修改结构体的值 todo 待完善
			if i == 1 {
			}
			// 字段值打印
			util.PrnType(reflectValue.Field(i))
			// tag标签
			util.PrnType(GetType(interfaceA).Field(i).Tag.Get("json"))
		}
		util.PrnLine()
	}

	// 传入的值做运算 - 先转换为int，如果类型不一致会报错，需要先采用断言判断类型
	//util.PrnType(reflectValue.Int() + 100)
}

func SetVal(interfaceA interface{}) {
	// elem - 获取指针指向的空间 - 修改原值
	reflect.ValueOf(interfaceA).Elem().SetInt(123456)
}

func IsStruct(interfaceA interface{}) bool {
	return GetKind(interfaceA) == reflect.Struct
}

// Type 类型、Kind 类别，可能相同，也可能不同
func GetKind(interfaceA interface{}) reflect.Kind {
	//reflect.ValueOf(interfaceA).Kind() - 另一种获取方式
	return GetType(interfaceA).Kind()
}

func GetType(interfaceA interface{}) reflect.Type {
	return reflect.TypeOf(interfaceA)
}

func GetVal(interfaceA interface{}) reflect.Value {
	return reflect.ValueOf(interfaceA)
}
